package com.ruoyi.act.module.service.impl;

import com.ruoyi.act.module.domain.ActHistory;
import com.ruoyi.act.module.service.IHistoryService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.*;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class HistoryServiceImpl implements IHistoryService {

    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;

    @Override
    public List<HistoricTaskInstance> findTaskList(ActHistory actHistory) {
        HistoricTaskInstanceQuery instanceQuery = historyService.createHistoricTaskInstanceQuery();
        instanceQuery.processInstanceId(actHistory.getId());
        if (StringUtils.isNotBlank(actHistory.getTaskAssignee())) {
            instanceQuery.taskAssignee(actHistory.getTaskAssignee());
        }
        instanceQuery.orderByTaskCreateTime();
        if (actHistory.getIsAsc()) {
            instanceQuery.asc();
        } else {
            instanceQuery.desc();
        }
        List<HistoricTaskInstance> list = instanceQuery.list();
        return list;
    }

    @Override
    public List<Map<String, Object>> findActivityList(ActHistory actHistory) {
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        instanceQuery.processInstanceId(actHistory.getId());
        if (StringUtils.isNotBlank(actHistory.getTaskAssignee())) {
            instanceQuery.taskAssignee(actHistory.getTaskAssignee());
        }
        instanceQuery.orderByHistoricActivityInstanceEndTime();
        if (actHistory.getIsAsc()) {
            instanceQuery.asc();
        } else {
            instanceQuery.desc();
        }
        List<HistoricActivityInstance> list = instanceQuery.activityType("userTask").list();

        List<Map<String, Object>> mapList = new ArrayList<>();
        list.forEach(info -> {
            if (StringUtils.isNotBlank(info.getAssignee())) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", info.getId());
                map.put("assignee", info.getAssignee());
                map.put("taskId", info.getTaskId());
                map.put("startTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(info.getStartTime()));
                map.put("endTime", info.getEndTime() == null ? "" : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(info.getEndTime()));
                map.put("activityName", info.getActivityName());

                HistoricVariableInstanceQuery variableInstanceQuery = historyService.createHistoricVariableInstanceQuery();
                variableInstanceQuery.processInstanceId(actHistory.getId()).taskId(info.getTaskId())
                        .variableName(actHistory.getVariableName());
                List<HistoricVariableInstance> variables = variableInstanceQuery.list();
                if (variables.size() > 0) {
                    map.put(actHistory.getVariableName(), variables.get(0).getValue());
                } else {
                    map.put(actHistory.getVariableName(), "");
                }
                mapList.add(map);
            }
        });
        return mapList;
    }

    @Override
    public InputStream generateDiagram(ActHistory actHistory) throws TranscoderException, IOException {
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        HistoricProcessInstance historicProcessInstance = query.processInstanceId(actHistory.getId()).singleResult();

        if (historicProcessInstance != null) {
            BpmnModel model = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
            InputStream inputStream = null;

            if (actHistory.getIsTrue()) {
                // 默认查询 颜色节点 异常后查询不带颜色的节点
                try {
                    inputStream = generator.generateDiagram(model,
                            runtimeService.getActiveActivityIds(actHistory.getId()),
                            new ArrayList<>(),
                            "宋体",
                            "宋体",
                            "宋体");
                } catch (Exception e) {
                    inputStream = generator.generateDiagram(model,
                            Collections.emptyList(),
                            new ArrayList<>(),
                            "宋体",
                            "宋体",
                            "宋体");
                }
            } else {
                inputStream = generator.generateDiagram(model,
                        Collections.emptyList(),
                        new ArrayList<>(),
                        "宋体",
                        "宋体",
                        "宋体");
            }

            TranscoderInput input = new TranscoderInput(inputStream);
            PNGTranscoder transcoder = new PNGTranscoder();
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            TranscoderOutput output = new TranscoderOutput(outStream);
            transcoder.transcode(input, output);
            byte[] result = outStream.toByteArray();
            InputStream in = new ByteArrayInputStream(result);
            outStream.close();
            return in;
        }
        return null;
    }


}
